using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DragonAwakening.Core.World
{
    /// <summary>
    /// World data processor.
    /// </summary>
    public interface IWorldDataProcessor
    {
        /// <summary>
        /// Process the data stream.
        /// </summary>
        /// <param name="data">Data stream.</param>
        /// <param name="index">Index in the stream.</param>
        /// <returns></returns>
        void Process(string data, int index);
    }

    /// <summary>
    /// World data processor.
    /// </summary>
    public abstract class WorldDataProcessor : IWorldDataProcessor
    {
        /// <summary>
        /// Next processor.
        /// </summary>
        protected IWorldDataProcessor next;

        /// <summary>
        /// The world.
        /// </summary>
        protected IWorld world;

        /// <summary>
        /// Initializes the processor.
        /// </summary>
        /// <param name="next">Next processor in the chain.</param>
        /// <param name="world">The world.</param>
        protected WorldDataProcessor(IWorldDataProcessor next, IWorld world)
        {
            if (world == null)
            {
                throw new ArgumentNullException("world", "The world shall not be null.");
            }

            this.next = next;
            this.world = world;
        }

        /// <summary>
        /// Processes the data chain.
        /// </summary>
        public abstract void Process(string data, int index);

        /// <summary>
        /// Tries to read the chunk from the data stream.
        /// </summary>
        /// <param name="data">Data stream.</param>
        /// <param name="currentIndex">Current stream index.</param>
        /// <param name="chunk">Data chunk.</param>
        /// <returns>Next index.</returns>
        protected int TryReadDataChunk(string data, int currentIndex, out string chunk)
        {
            int length = data.Length;
            if (currentIndex < length && currentIndex >= 0)
            {
                int nextIndex;
                if (data[currentIndex] == '{')
                {
                    nextIndex = data.IndexOf('}', currentIndex);
                    nextIndex = nextIndex == -1 ? -1 : nextIndex + 1;
                }
                else
                {
                    nextIndex = data.IndexOf(',', currentIndex);
                }

                if (nextIndex == -1)
                {
                    nextIndex = data.Length;
                }

                int chunkLength = nextIndex - currentIndex;
                if (chunkLength > 0)
                {
                    chunk = data.Substring(currentIndex, chunkLength);
                }
                else
                {
                    chunk = null;
                }

                return nextIndex + 1;
            }
            else
            {
                // [LOG] Info: Invocaion with index out of data range. Possible error in processor logic.

                chunk = null;
                return -1;
            }
        }

        /// <summary>
        /// Invokes next processor in the chain.
        /// </summary>
        protected void InvokeNextProcessor(string data, int index)
        {
            if (this.next != null)
            {
                this.next.Process(data, index);
            }
        }
    }
}
